package de.toolschmied.jjas.client.widgets.toolbar;

import java.util.HashMap;
import java.util.LinkedList;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;

/**
 * A Simple toolbar which allows users to add "Actions"
 *
 * Actions of different types (Push, Toggle or Radio) lead to differnt
 * types of buttons being created (actually, buttons with different traits).
 *
 */
public class Toolbar extends Composite {

	public static final String STYLE_NAME = "toolbar";
	public static final String SEPARATOR_STYLE_NAME = "withSeparator";

	private final HorizontalPanel panel = new HorizontalPanel();
	private final LinkedList<ToolbarButton> buttons = new LinkedList<ToolbarButton>();
	private final HashMap<String, RadioTrait> radioTraits = new HashMap<String, Toolbar.RadioTrait>();
	
	public Toolbar() {
		initWidget(panel);
		setStylePrimaryName(STYLE_NAME);
	}

	public void showSeparator() {
		addStyleName(SEPARATOR_STYLE_NAME);
	}
	
	/**
	 * Adds an action to the toolbar. Buttons will be automatically created depending
	 * on the type of action provided.
	 * 
	 * @param action the action to create the button for.
	 */
	public void add(Action action) {
		ToolbarButton button = getButton(action);
		buttons.add(button);
		panel.add(button);
	}
	
	public void setSelected(Action action) {
		for (ToolbarButton button : buttons) {
			boolean selected = button.getAction() == action;
			button.setDown(selected);
		}
	}
	
	public LinkedList<Action> getActions() {
		LinkedList<Action> actions = new LinkedList<Action>();
		for (ToolbarButton button : buttons) {
			actions.add(button.getAction());
		}
		return actions;
	}
	
	/**
	 * Gets a button based on the action Type.
	 * 
	 * @param action the action to create the button for.
	 * @return a toolbar button
	 */
	private ToolbarButton getButton(Action action) {
		switch(action.getType()) {
		case TOGGLE:
			return getToggleButton(action);
		case RADIO:
			return getRadioButton(action);
		case PUSH:
		default:
			return getPushButton(action);
		}
	}

	/**
	 * Creates a new Push button.
	 * 
	 * @param action the action to create the button for.
	 * @return a toolbar button
	 */
	private ToolbarButton getPushButton(Action action) {
		ToolbarButton button = new ToolbarButton(action);
		return button;
	}

	/**
	 * Creats a toggle button
	 * 
	 * @param action the action to create the button for.
	 * @return a toolbar button
	 */
	private ToolbarButton getToggleButton(Action action) {
		ToolbarButton button = new ToolbarButton(action);
		ToggleTrait toggleTrait = new ToggleTrait();
		button.addClickHandler(toggleTrait);
		return button;
	}
	
	/**
	 * Creates a new button and adds it to it's group in which only one button can be selected.
	 * If no group is provided, the "null" group will be used.
	 * 
	 * @param action the action to create a radio button for
	 * @return a toolbar button
	 */
	private ToolbarButton getRadioButton(Action action) {
		ToolbarButton button = new ToolbarButton(action);
		String group = action.getGroup();
		RadioTrait radioTrait = radioTraits.get(group);
		if (radioTrait == null) {
			radioTrait = new RadioTrait();
			radioTraits.put(group, radioTrait);
		}
		radioTrait.addButton(button);
		
		return button;
	}


	/**
	 * A ToggleTrait listens for clicks on Toolbar button and toggles
	 * between selected and unselected.
	 */
	private class ToggleTrait implements ClickHandler {

		@Override
		public void onClick(ClickEvent event) {
			ToolbarButton button = (ToolbarButton) event.getSource();
			button.setDown(!button.isDown());
		}
		
	}

	/**
	 * A RadioTrait keeps track of all the buttons in a group and
	 * only allows one of the buttons to be selected at a time.
	 */
	private class RadioTrait implements ClickHandler {

		private final LinkedList<ToolbarButton> buttons = new LinkedList<ToolbarButton>();
		
		@Override
		public void onClick(ClickEvent event) {
			ToolbarButton selected = (ToolbarButton) event.getSource();
			for (ToolbarButton button : buttons) {
				if (button != selected) {
					button.setDown(false);
				}
			}
			selected.setDown(true);
		}
		
		public void addButton(ToolbarButton button) {
			buttons.add(button);
			button.addClickHandler(this);
		}
		
	}

}
